using System;

using SMGCore.EventSys;
using Game.Networking.Events;
using Game.Networking.Server;

using MemoryPack;

namespace Game.Networking {
	public class C_HandshakeMessageHandler : BaseClientMessageHandler {
		public override ClientPacketID CommandId {
			get {
				return ClientPacketID.Identification;
			}
		}

		public override void ProcessMessage(ClientState client, byte[] rawCommand) {
			var server = ServerController.Instance;
			var command = MemoryPackSerializer.Deserialize<C_HandshakeMessage>(rawCommand);
			if ( !GameManager.Instance.Server.Initialized ) {
				server.ForceDisconnectClient(client, "Server is starting!", Utils.DisconnectReason.ServerNotReady);
				return;
			}
			if ( command.ProtocolVersion != ServerController.ProtocolVersion ) {
				server.ForceDisconnectClient(client, string.Format("Wrong protocol version. Server: {0}, yours: {1}", ServerController.ProtocolVersion, command.ProtocolVersion), Utils.DisconnectReason.DifferentProtocol);
				return;
			}
			if ( server.IsClientBanned(client.IpAdress, client.UserName, out var ban) ) {
				server.ForceDisconnectClient(client, string.Format("You are banned until {0} due to: {1}", ban.BanEnd.ToShortDateString(), ban.Reason), Utils.DisconnectReason.Banned);
				return;
			}

			foreach ( var cli in server.Clients.Values ) {
				if ( cli.UserName == command.ClientName ) {
					server.ForceDisconnectClient(client, string.Format("User with name {0} is already connected. Force disconnecting.", command.ClientName), Utils.DisconnectReason.UserAlreadyConnected);
					return;
				}
			}

			var authResult = server.TryAuthenticate(client, command.ClientName, command.Password, out var isNew);
			if ( authResult != AuthResult.Success ) {
				server.ForceDisconnectClient(client, authResult == AuthResult.WrongPassword ? "Wrong password!" : "Registration closed, server is invite-only", Utils.DisconnectReason.RegistrationClosed);
				return;
			}
					   			
			client.ConnectionTime = DateTime.Now;
			client.CurrentState = CState.Initialize;
			EventManager.Fire(new OnClientConnected { ConnectionId = client.ConnectionID, State = client });
			UnityEngine.Debug.LogFormat("Server: client with name {0} connected.", client.UserName);
			ServerChatManager.Instance.BroadcastFromServer(ChatMessageType.Info, string.Format("{0} connected to the server.", command.ClientName));
			
		}
	}
}
